//
// Created by weng on 24-3-19.
//
#ifndef BASALT_MEM_MANAGE_HPP
#define BASALT_MEM_MANAGE_HPP

#include <new>
#include <list>
#include <iostream>
#include <unistd.h>

using namespace std;

namespace basalt {

union NodeObj
{
  union NodeObj *next;  // 自由链表使用, 下一块儿block的地址
  char client_data[1];  // 用户使用
};


/*
* 当前为图像专用
*/
class MemoryPool
{
public:
  MemoryPool() = default;

  ~MemoryPool() {
    for (char *p_mem: mem_allocated_list_) {
      std::free(p_mem);
    }
    mem_allocated_list_.clear();
    header_fl_ = nullptr;
  }


  bool isNotInit() const {
    return POOL_ONCE_ALLOC_BLOCKS == 0 || ONE_BLOCK_SIZE == 0;
  }


  /*
  * MemoryPool使用前，必须进行调用initMemoryPool。
  * 直接构造自由链表，分配一个初始的大块儿内存
  * @param one_block_size 内存池中，一块儿内存的大小. 752 * 480
  * @param one_alloc_blocks 一次调用OS底层申请内存时，初始化的内存块数
  */
  void initMemoryPool(size_t one_block_size, size_t one_alloc_blocks = 15) {
    ONE_BLOCK_SIZE = one_block_size;
    POOL_ONCE_ALLOC_BLOCKS = one_alloc_blocks;
    // std::cout << "Construct of MemoryPool for create a Chunk memory block ( one_block_size * total ): "
    //           << one_block_size << ", " << POOL_ONCE_ALLOC_BLOCKS << "\n";
    allocBlock(true);
  }

  /**
  * 分配函数，从自由链表调出一个小块, 分配给外部新创建的对象
  * @param one_block_size
  * @return
  */
  void *alloc() {
    Lock();
    union NodeObj *result = header_fl_;
    // std::cout << "\033[1;2;3;33mmem check1: " << result << ", " << header_fl_ << "\033[0m" << std::endl;
    // union NodeObj *cur_obj, *next_obj; // NOLINT(*-isolate-declaration)

    if (result != nullptr) {
      // weng bug found 240515 18:23: 段错误
      // 大概率是和free修改冲突导致
      // std::cout << "\033[1;2;3;33mmem check2: "  << result  << ", " << header_fl_ << ", " << header_fl_->next << "\033[0m" << std::endl;
      header_fl_ = result->next;
      available_blocks_--;
    }
    else {
      // 如果为空，那么就是没有了。从堆中补充自由链表, 注意第一个地址返回
      // std::cout << "\033[1;2;3;33malloc a new memory block to extend pool size. \033[0m\n";
      result = allocBlock(false);
    }
    Unlock();

    // std::cout << "\033[2;3;37mAlloc: \033[1;45m" << getPools() << ", " << getBlocks() << "\033[0m\n";
    return result;
  }


  /**
  * 释放一个节点，对该块儿内存进行资源回收
  * @param ptr
  * @param n
  */
  void free(void *ptr, size_t n)  // 释放函数，内存块加入自由链表
  {
    Lock();
    auto *p = (union NodeObj *) ptr;
    p->next = header_fl_;
    // std::cout << "\033[2;3;34mmmem check3, free: " << header_fl_ << ", " << p << ", " << &p << "next: " << p->next << ", add: " << & (p->next) << "\033[0m" << std::endl;
    header_fl_ = p;
    available_blocks_++;
    // std::cout << "\033[2;3;34mmmem check4, free: " << header_fl_ << ", " << p << ", " << &p << "next: " << p->next << ", add: " << & (p->next)  << "\033[0m" << std::endl;
    // std::cout << "\033[2;3;37mmmem check5, Deallocate/Free: \033[1;30;45m" << getPools() << ", " << getBlocks() << "\033[0m\n";
    Unlock();
  }

  /**
  *
  * [[nodiscard("MemoryPool::GetChunks")]] int GetChunks() const { return available_chunks_;} // C++20
  * @return 返回自由链表中可用节点的个数
  */
  [[nodiscard]] size_t getBlocks() const {
    return available_blocks_;
  }

  [[nodiscard]] size_t getPools() const {
    return mem_allocated_list_.size();
  }


  void Lock()
  {
    while (!__sync_bool_compare_and_swap(&mutex, lock, 1)) {
      usleep(200);
    }
  }

  void Unlock() {
    __sync_bool_compare_and_swap(&mutex, unlock, 0);
  }


private:

  /**
  * allocate a new pool
  * @param is_first_init_flag 是否为初始分配
  * @return
  */
  NodeObj *allocBlock(bool is_first_init_flag = false) {

    // 自由链表为空，分配可以容纳BLOCK_SIZE个的n块
    union NodeObj *current_obj, *next_obj; // NOLINT(*-isolate-declaration)
    union NodeObj *result = nullptr;
    int memory_block_idx_start = 0;


    // 分配 BLOCK_SIZE * n 大内存
    char *mem_block_whole = (char *) malloc(POOL_ONCE_ALLOC_BLOCKS * ONE_BLOCK_SIZE);
    // std::cout << "block pool new: " << (void *) & (mem_block_whole[0]) << ", " << (void *) mem_block_whole << std::endl;
    if (mem_block_whole == nullptr) {
      std::cout << "\033[1;2;3;41mMemory Pool malloc memory failed, no more heap memory. \033[0m\n";
      return result;
    }
    mem_allocated_list_.push_back(mem_block_whole);
    if (!is_first_init_flag) {
      result = (union NodeObj *) mem_block_whole;
      mem_block_whole += ONE_BLOCK_SIZE;
      memory_block_idx_start = 1;
    }
    header_fl_ = current_obj = next_obj = (union NodeObj *) mem_block_whole; // 首地址


    // 将内存块组成自由链表
    for (size_t i = memory_block_idx_start; i < POOL_ONCE_ALLOC_BLOCKS - 1; i++) {
      next_obj = (union NodeObj *) ((char *) next_obj + ONE_BLOCK_SIZE); // 找出下一个节点地址
      current_obj->next = next_obj; // 存储下一个节点地址
      // std::cout << "current_obj: " << current_obj  << "  next: " << current_obj->next << std::endl;
      current_obj = next_obj; // 更新当前节点，为下次做准备
    }
    current_obj->next = nullptr; // 0或nullptr均可。尾部节点置为空。
    // std::cout << "final next: " << current_obj->next << std::endl;
    available_blocks_ = is_first_init_flag ? POOL_ONCE_ALLOC_BLOCKS : POOL_ONCE_ALLOC_BLOCKS - 1;


    // std::cout << "\033[2;3;32mAlloc Block success！\033[0m\n";

    return result;
  }

  size_t POOL_ONCE_ALLOC_BLOCKS = 0;  // 初始化节点个数
  size_t ONE_BLOCK_SIZE = 0;
  NodeObj *header_fl_ = nullptr;
  size_t available_blocks_ = 0;
  std::list<char *> mem_allocated_list_;

  int mutex;
  int lock;
  int unlock;
};

}
#endif //BASALT_MEM_MANAGE_HPP
